In [329]:
import pandas as pd
import altair as alt
import datetime as dt
In [331]:
job_market=pd.read_csv('ai_job_market.csv')
job_market.head()
Out[331]:
job_id company_name industry job_title skills_required experience_level employment_type location salary_range_usd posted_date company_size tools_preferred
0 1 Foster and Sons Healthcare Data Analyst NumPy, Reinforcement Learning, PyTorch, Scikit... Mid Full-time Tracybury, AR 92860-109598 2025-08-20 Large KDB+, LangChain
1 2 Boyd, Myers and Ramirez Tech Computer Vision Engineer Scikit-learn, CUDA, SQL, Pandas Senior Full-time Lake Scott, CU 78523-144875 2024-03-22 Large FastAPI, KDB+, TensorFlow
2 3 King Inc Tech Quant Researcher MLflow, FastAPI, Azure, PyTorch, SQL, GCP Entry Full-time East Paige, CM 124496-217204 2025-09-18 Large BigQuery, PyTorch, Scikit-learn
3 4 Cooper, Archer and Lynch Tech AI Product Manager Scikit-learn, C++, Pandas, LangChain, AWS, R Mid Full-time Perezview, FI 50908-123743 2024-05-08 Large TensorFlow, BigQuery, MLflow
4 5 Hall LLC Finance Data Scientist Excel, Keras, SQL, Hugging Face Senior Contract North Desireeland, NE 98694-135413 2025-02-24 Large PyTorch, LangChain
In [333]:
job_market['salary_min'] = job_market['salary_range_usd'].str.split('-').str[0].astype(int)
job_market['salary_max'] = job_market['salary_range_usd'].str.split('-').str[1].astype(int)
job_market['posted_date'] = pd.to_datetime(job_market['posted_date'], infer_datetime_format=True, errors='coerce')
job_market['posted_year']=job_market['posted_date'].dt.year
job_market['salary_avg'] = (job_market['salary_min'] + job_market['salary_max']) / 2
/var/folders/y4/fkn560k16c3__twnyy0m4jxr0000gn/T/ipykernel_52577/1968262285.py:3: UserWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, see https://pandas.pydata.org/pdeps/0004-consistent-to-datetime-parsing.html. You can safely remove this argument.
  job_market['posted_date'] = pd.to_datetime(job_market['posted_date'], infer_datetime_format=True, errors='coerce')
In [335]:
min_date = job_market['posted_date'].min()
max_date = job_market['posted_date'].max()
print(min_date, max_date)
2023-09-21 00:00:00 2025-09-19 00:00:00
In [337]:
## Bar CHart - Which experience level have the most job openings.
In [339]:
bar_chart = (
    alt.Chart(job_market, title='AI Job Postings by Experience Level')
    .transform_aggregate(
        count_jobs='count()',
        groupby=['experience_level']
    ).mark_bar()
    .encode(
        x=alt.X('experience_level:N', title='Experience Level', sort=['Entry', 'Mid', 'Senior']),
        y=alt.Y('count_jobs:Q', title='Number of Job Postings'),
        tooltip=[
            alt.Tooltip('experience_level:N', title='Level'),
            alt.Tooltip('count_jobs:Q', title='Postings')
        ]
    )
    .properties(width=300, height=250)
)
line_chart_monthly = (
    alt.Chart(job_market, title='AI Job Postings in each month(2023-2025)')
    .transform_timeunit(
        month_bin='yearmonth(posted_date)'
    )
    .transform_aggregate(
        jobs_per_month='count()',
        groupby=['month_bin']
    )
    .encode(x=alt.X('month_bin:T',title='Month',axis=alt.Axis(format='%b %Y', labelAngle=45)),
           y=alt.Y('jobs_per_month:Q',title='Number of Job Postings'),
        tooltip=[
            alt.Tooltip('month_bin:T', title='Month-Year'),
            alt.Tooltip('jobs_per_month:Q', title='Postings')
        ]
    )
    .mark_line(point=True)
    .properties(width=300, height=250)
)

scatter_entry = (
    alt.Chart(job_market, title='Entry-Level AI Roles vs Avg Salary')
    .transform_filter(
        alt.datum.experience_level == 'Entry'
    )
    .encode(
        x=alt.X('job_title:N', title='Industry'),
        y=alt.Y('salary_avg:Q', title='Average Salary (USD)'),

        tooltip=[
            alt.Tooltip('company_name:N', title='Company'),
            alt.Tooltip('job_title:N', title='Job Title'),
            alt.Tooltip('salary_min:Q', title='Min Salary'),
            alt.Tooltip('salary_max:Q', title='Max Salary')
        ]
    )
    .mark_circle(size=70, opacity=0.5)
    .properties(width=300, height=250)
)

bar_line_chart = line_chart_monthly | bar_chart | scatter_entry
bar_line_chart
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[339]:
In [341]:
industry_summary = (
    job_market
    .groupby('industry')
    .size()
    .reset_index(name='job_count')
    .sort_values('job_count', ascending=False)
)
overall_avg = industry_summary['job_count'].mean()
bars = (
    alt.Chart(industry_summary)
    .mark_bar(opacity=0.7, color='#4C78A8')
    .encode(
        y=alt.Y('job_count:Q', title='Number of AI Job Postings'),
        x=alt.X('industry:N', sort='-y', title='Industry'),
        tooltip=[
            alt.Tooltip('industry:N', title='Industry'),
            alt.Tooltip('job_count:Q', title='Job Postings')
        ]
    )
)
avg_line = (
    alt.Chart(pd.DataFrame({'avg_jobs': [overall_avg]}))
    .mark_rule(color='red', strokeDash=[6,3], strokeWidth=2)
    .encode(
        y='avg_jobs:Q',
        tooltip=[
            alt.Tooltip('avg_jobs:Q', title='Average Job Count')
        ]
    )
)
layered_industry_avg = (
    alt.layer(bars, avg_line)
    .properties(
        title='AI Job Postings by Industry (with Overall Average)',
        width=300,
        height=250
    )
)
layered_industry_avg
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[341]:
In [343]:
jobrole_summary = (
    job_market
    .groupby('job_title')
    .size()
    .reset_index(name='job_count')
    .sort_values('job_count', ascending=False)
)
overall_avg = jobrole_summary['job_count'].mean()
bars = (
    alt.Chart(jobrole_summary)
    .mark_bar(opacity=0.7, color='#4C78A8')
    .encode(
        y=alt.Y('job_count:Q', title='Number of AI Job Postings'),
        x=alt.X('job_title:N', sort='-y', title='job_title'),
        tooltip=[
            alt.Tooltip('job_title:N', title='job_title'),
            alt.Tooltip('job_count:Q', title='Job Postings')
        ]
    )
)
avg_line = (
    alt.Chart(pd.DataFrame({'avg_jobs': [overall_avg]}))
    .mark_rule(color='red', strokeDash=[6,3], strokeWidth=2)
    .encode(
        y='avg_jobs:Q',
        tooltip=[
            alt.Tooltip('avg_jobs:Q', title='Average Job Count')
        ]
    )
)
layered_role_avg = (
    alt.layer(bars, avg_line)
    .properties(
        title='AI Job Postings by role (with Overall Average)',
        width=300,
        height=250
    )
)
layered_role_avg
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[343]:
In [345]:
automation_dataanalyst_base = (
    alt.Chart(job_market)
    .transform_filter(
        (alt.datum.industry == 'Automotive') &
        (alt.datum.job_title == 'Data Analyst')
    )
    .transform_aggregate(
        job_count='count()',
        mean_salary='mean(salary_avg)',
        groupby=['employment_type']
    )
)
bars = (
    automation_dataanalyst_base
    .mark_bar(color='#4C78A8')
    .encode(
        x=alt.X('employment_type:N', title='Employment Type'),
        y=alt.Y('job_count:Q', title='Number of Job Postings'),
        tooltip=[
            alt.Tooltip('employment_type:N', title='Employment Type'),
            alt.Tooltip('job_count:Q', title='Job Count'),
            alt.Tooltip('mean_salary:Q', title='Average Salary (USD)', format=',.0f')
        ]
    )
)
labels = (
    automation_dataanalyst_base
    .mark_text(
        align='center',
        baseline='bottom',
        dy=-5,  # distance above bar
        color='black',
        fontSize=12
    )
    .encode(
        x=alt.X('employment_type:N'),
        y=alt.Y('job_count:Q'),
        text=alt.Text('mean_salary:Q', format='$,.0f')  # formatted as currency
    )
)
automation_dataanalyst = (
    alt.layer(bars, labels)
    .properties(
        title='Automotive Industry – Data Analyst Roles by Employment Type',
        width=300,
        height=250
    )
)

automation_dataanalyst
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[345]:
In [347]:
entry_ds_yearly = (
    alt.Chart(job_market, title='Entry-Level Data Scientist Job Postings(2023-2025)')
    .transform_filter(
        (alt.datum.experience_level == 'Entry') &
        (alt.datum.job_title == 'Data Scientist')
    )
    .transform_calculate(
        year="year(datum.posted_date)"
    )
    .transform_aggregate(
        job_count='count()',
        groupby=['year', 'industry']
    )
    .encode(
        x=alt.X('year:O', title='Year'),
        y=alt.Y('job_count:Q', title='Number of Data Science Job Posts'),
        color=alt.Color('industry:N', title='Industry'),
        tooltip=[
            alt.Tooltip('year:O', title='Year'),
            alt.Tooltip('industry:N', title='Industry'),
            alt.Tooltip('job_count:Q', title='Job Postings')
        ]
    )
    .mark_line(point=True)
    .properties(width=300, height=250)
)

entry_ds_yearly
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[347]:
In [349]:
scatter_faceted_employment = (
    alt.Chart(job_market)
    .transform_filter(
        alt.datum.job_title == 'Data Analyst'
    )
    .encode(
        x=alt.X(
            'employment_type:N',
            title='Employment Type'
        ),
        y=alt.Y(
            'salary_avg:Q',
            title='Average Salary (USD)',
            scale=alt.Scale(zero=False)
        ),
        color=alt.Color(
            'employment_type:N',
            title='Employment Type',
            legend=None
        ),
        tooltip=[
            alt.Tooltip('industry:N', title='Industry'),
            alt.Tooltip('employment_type:N', title='Employment Type'),
            alt.Tooltip('company_name:N', title='Company'),
            alt.Tooltip('avg_salary:Q', title='Avg Salary (USD)', format=',.0f')
        ]
    )
    .mark_circle(size=90, opacity=0.6)
    .properties(width=75, height=250)
    .facet(
        column=alt.Column(
            'industry:N',
            title='Industry'
        )
    )
)

scatter_faceted_employment
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[349]:
In [351]:
dashboard = alt.vconcat(alt.vconcat(
    bar_line_chart,
    alt.hconcat(alt.hconcat(layered_industry_avg,layered_role_avg),automation_dataanalyst)
),alt.hconcat(scatter_faceted_employment,entry_ds_yearly).resolve_legend(
    color='independent'
)).resolve_legend(
    color='independent'
)
dashboard
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
/opt/anaconda3/lib/python3.12/site-packages/altair/utils/core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[351]:

AI Job Postings by Month (Line Chart)

  • This line chart introduces the dashboard by showing how AI job postings have changed over time from 2023 to 2025. A line chart is ideal for continuous temporal data, helping the viewer immediately detect seasonality, peaks, or declines in hiring. Points are overlaid on the line to emphasize individual months. Placing this chart at the top it establishes the overall temporal trend of the AI job market and sets context for all subsequent analyses.

AI Job Postings by Experience Level (Bar Chart)

  • Following the trend line, this bar chart summarizes the Number of job postings by experience level (Entry, Mid, Senior). Bar charts excel at categorical comparisons, and the uniform color scheme visually connects to the previous plot while shifting focus from when jobs are posted to who is being hired. Its position next to the line chart allows viewers to link hiring volume over time with the experience-level mix.

Entry-Level AI Roles vs. Average Salary (Scatter Plot)

  • Since Entry-level positions account for the highest number of AI job postings, this scatter plot focuses on understanding the average salary distribution across different roles at the entry level. Each point represents a job posting, plotted by role on the x-axis and average salary on the y-axis. A scatter plot is ideal here because it captures both variation and spread—allowing clear visibility into how salaries differ not only between roles but also within the same role category.

After exploring how salaries vary across entry level roles, I wanted to extend my analysis to understand which industries are driving overall AI hiring demand.

AI Job Postings by Industry (with Overall Average) Layered Bar Plot

  • This layered bar chart displays the number of AI job postings in each industry, with a red dashed line indicating the overall market average. The combination of bars and a reference line enables quick identification of industries hiring above or below average. Using layering allows individual industry values and the benchmark to coexist in a single, uncluttered view.

Next I wanted to explore which specific roles are contributing most to this hiring activity. AI Job Postings by Role (with Overall Average) – Layered Bar Plot

  • This chart is similar to the preious one but groups data by job title instead of industry. Each bar represents the number of job postings for a particular role, while a red dashed line shows the overall average across all roles. Positioned beside the industry chart, this plot reveal industries hiring and which roles are most in demand across the market.

From the previous two layered plots, we observed that the Automotive industry had one of the highest numbers of postings, and within it, the Data Analyst role appeared most frequently. To explore this pattern further, we wanted to visualize the number of Data Analyst positions within the Automotive industry and examine how average salary differs across employment types.

Automotive Industry - Data Analyst Roles by Employment Type (Filtered + Calculated + Labeled Bar Chart)

  • This plot filters data with Data Analyst roles in the Automotive industry. Each bar represents a distinct employment type (Full-time, Contract, etc.), with the bar height showing the number of postings and a label above each bar displaying the average salary, calculated directly from the salary_range_usd field. This chart combines filtering, aggregation, and calculation transformations. Placed at the end of the second row, it acts as a detailed visualization from a broad structural view to an in-depth look at one specific, high-activity industry and role combination.

This bar chart reveals that the average salary is higher for internships than for full-time roles within Data Analyst positions in the Automotive industry an unusual pattern that prompted further analysis. To determine whether a similar trend occurs across other industries, I created the following faceted scatter plot.

Data Scientist Salaries by Employment Type (Faceted Scatter Plot)

  • This visualization explores how Data Analyst salaries vary by employment type across multiple industries. Each facet (small chart) represents a single industry, while each point represents a job posting colored by employment type. The x-axis shows employment type categories, and the y-axis displays the computed average salary derived from the salary_range_usd field. Faceting allows consistent comparison across industries without overlapping data in a single chart. Positioned at the beginning of the third row, this plot transitions the dashboard’s focus from a single-industry case study to a cross-industry comparison, helping us see whether the unusual pay structure observed in the Automotive industry persists in the broader AI job market.

Finally in the last plot I wanted to check the trend for data scientist for the past 2 years(2023 - 2025) across varios industries. Entry-Level Data Scientist Job Postings (Line Chart by Year in each Industry)

  • This multi-line chart visualizes the annual trend of Data Scientist job postings across industries. Each line represents one industry, allowing direct comparison of hiring trajectories. The x-axis encodes the year, and the y-axis shows the number of postings, while color differentiates industries. Using a line chart is ideal for temporal comparisons, as it highlights overall direction and momentum in hiring.
In [ ]: